package com.fintech.pangu.autoconfigure.security.authentication;

import com.fintech.pangu.autoconfigure.security.authentication.token.AuthenticationTokenMarkerConfiguration;
import com.fintech.pangu.autoconfigure.security.authentication.token.DefaultAuthenticationTokenAutoConfiguration;
import com.fintech.pangu.autoconfigure.security.authentication.token.JwtAuthenticationTokenAutoConfiguration;
import com.fintech.pangu.autoconfigure.security.properties.PanGuSecurityProperties;
import com.fintech.pangu.security.authentication.config.ApiLoginPanGuHttpSecurityConfig;
import com.fintech.pangu.security.authentication.handler.ApiLoginAuthenticationFailureHandler;
import com.fintech.pangu.security.authentication.handler.ApiLoginAuthenticationSuccessHandler;
import com.fintech.pangu.security.authentication.handler.ApiLogoutHandler;
import com.fintech.pangu.security.authentication.handler.ApiLogoutSuccessHandler;
import com.fintech.pangu.security.authentication.token.AuthenticationTokenResponder;
import com.fintech.pangu.security.authentication.token.AuthenticationTokenServices;
import com.fintech.pangu.security.config.PanGuHttpSecurityConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * Api Login自动配置类
 * 注入ApiLoginAuthenticationFilter认证Filter及其成功、失败处理器
 *
 * @author Trust_FreeDom
 */
@Configuration
@EnableConfigurationProperties(PanGuSecurityProperties.class)
@ConditionalOnProperty(value = "pangu.security.authentication.api-login-enable", havingValue = "true", matchIfMissing = false)
//先注册AuthenticationTokenMarkerConfiguration.Marker的Bean定义再开始AuthenticationToken自动配置，否则无可用TokenService
@AutoConfigureBefore({ DefaultAuthenticationTokenAutoConfiguration.class, JwtAuthenticationTokenAutoConfiguration.class})
public class ApiAuthenticationAutoConfiguration {

    /**
     * 注入AuthenticationTokenMarkerConfiguration.Marker标记，开启AuthenticationToken服务及存储的自动配置
     */
    @Bean
    @ConditionalOnMissingBean(AuthenticationTokenMarkerConfiguration.Marker.class)
    public AuthenticationTokenMarkerConfiguration.Marker authenticationTokenMarkerBean() {
        return new AuthenticationTokenMarkerConfiguration.Marker();
    }


    /**
     * PanGu安全相关所有配置
     */
    @Autowired
    private PanGuSecurityProperties panGuSecurityProperties;


    /**
     * Api Login 安全配置
     * 向Spring Security过滤器链注入ApiLoginAuthenticationFilter、ApiLogoutFilter
     * @param apiLoginAuthenticationSuccessHandler  Api登录成功处理器
     * @param apiLoginAuthenticationFailureHandler  Api登录失败处理器
     * @param apiLogoutHandler  Api登出处理器
     * @param apiLogoutSuccessHandler  Api登出成功处理器
     * @return
     */
    @Bean
    public PanGuHttpSecurityConfigurer apiLoginPanGuHttpSecurityConfig(
            AuthenticationSuccessHandler apiLoginAuthenticationSuccessHandler,
            AuthenticationFailureHandler apiLoginAuthenticationFailureHandler,
            LogoutHandler apiLogoutHandler,
            LogoutSuccessHandler apiLogoutSuccessHandler){
        ApiLoginPanGuHttpSecurityConfig config = new ApiLoginPanGuHttpSecurityConfig();

        config.setApiLoginAuthenticationSuccessHandler(apiLoginAuthenticationSuccessHandler);
        config.setApiLoginAuthenticationFailureHandler(apiLoginAuthenticationFailureHandler);
        config.setApiLogoutHandler(apiLogoutHandler);
        config.setApiLogoutSuccessHandler(apiLogoutSuccessHandler);

        return config;
    }


    /**
     * Api Login 登录成功处理器
     * 使用AuthenticationTokenServices生成、获取token，并完成token存储
     * 使用AuthenticationTokenResponder创建对token的响应
     * @param tokenServices
     * @param tokenResponder
     * @return
     */
    @Bean
    public AuthenticationSuccessHandler apiLoginAuthenticationSuccessHandler(AuthenticationTokenServices tokenServices, AuthenticationTokenResponder tokenResponder){
        ApiLoginAuthenticationSuccessHandler apiLoginAuthenticationSuccessHandler = new ApiLoginAuthenticationSuccessHandler();
        apiLoginAuthenticationSuccessHandler.setAuthenticationTokenServices(tokenServices);   // token服务
        apiLoginAuthenticationSuccessHandler.setAuthenticationTokenResponder(tokenResponder); // token响应器
        return apiLoginAuthenticationSuccessHandler;
    }


    /**
     * Api Login 登录失败处理器
     * @return
     */
    @Bean
    public AuthenticationFailureHandler apiLoginAuthenticationFailureHandler(){
        return new ApiLoginAuthenticationFailureHandler();
    }


    /**
     * Api Logout 登出处理器
     * @return
     */
    @Bean
    public LogoutHandler apiLogoutHandler(){
        return new ApiLogoutHandler();
    }

    /**
     * Api Logout 登出成功处理器
     * @param tokenResponder
     * @return
     */
    @Bean
    public LogoutSuccessHandler apiLogoutSuccessHandler(AuthenticationTokenResponder tokenResponder){
        ApiLogoutSuccessHandler apiLogoutSuccessHandler = new ApiLogoutSuccessHandler();
        apiLogoutSuccessHandler.setAuthenticationTokenResponder(tokenResponder); // token响应器
        return apiLogoutSuccessHandler;
    }

}
